Crate derive_visitor
source ·Expand description
This crate derives visitor pattern for arbitrary data structures. This pattern is particularly useful when dealing with complex nested data structures, abstract trees and hierarchies of all kinds.
The main building blocks of this crate are two derivable traits:
Visitor
andVisitorMut
implementations walk through data structures and accumulate some information;Drive
andDriveMut
implementations are data structures that know how to drive a visitor through themselves.
Please refer to these traits’ documentation for more details.
§Example
§Immutable visitor that counts items in a tree
use derive_visitor::{Visitor, Drive};
#[derive(Drive)]
struct Directory {
#[drive(skip)]
name: String,
items: Vec<DirectoryItem>,
}
#[derive(Drive)]
enum DirectoryItem {
File(File),
Directory(Directory),
}
#[derive(Drive)]
struct File {
#[drive(skip)]
name: String,
}
#[derive(Visitor, Default)]
#[visitor(File(enter), Directory(enter))]
struct Counter {
files: u32,
directories: u32
}
impl Counter {
fn enter_file(&mut self, _file: &File) {
self.files += 1;
}
fn enter_directory(&mut self, _directory: &Directory) {
self.directories += 1;
}
}
let mut counter = Counter::default();
let example_directory = Directory {
name: "root".into(),
items: vec![
DirectoryItem::Directory(
Directory {
name: "home".into(),
items: vec![
DirectoryItem::File(File { name: "README.md".into() }),
DirectoryItem::File(File { name: "Star Wars.mov".into() })
]
}
),
DirectoryItem::Directory(
Directory { name: "downloads".into(), items: vec![] }
)
],
};
example_directory.drive(&mut counter);
assert_eq!(counter.files, 2);
assert_eq!(counter.directories, 3);
§Mutable visitor that alters a tree
use derive_visitor::{VisitorMut, DriveMut};
#[derive(DriveMut)]
struct Tree {
#[drive(skip)]
name: String,
children: Vec<Tree>
}
#[derive(VisitorMut, Default)]
#[visitor(Tree(enter))]
struct Renamer {
from: &'static str,
to: &'static str,
}
impl Renamer {
fn enter_tree(&mut self, tree: &mut Tree) {
tree.name = tree.name.replace(self.from, self.to);
}
}
let mut my_tree = Tree{
name: "old parent".to_string(),
children: vec![
Tree {
name: "old child".to_string(),
children: vec![]
}
]
};
my_tree.drive_mut(&mut Renamer{from: "old", to: "new"});
assert_eq!(my_tree.name, "new parent");
assert_eq!(my_tree.children[0].name, "new child");
§Features
std-types-drive
- implement Drive for primitive types and String type from std. It is recommended to either skip these types in yourDrive
implementation, or to wrap them with newtypes, so this feature is disabled by default. However it might be useful when driving through autogenerated structs.
Structs§
- Type returned by visitor_fn.
Enums§
- Defines whether an item is being entered or exited by a visitor.
Traits§
- A data structure that can drive a visitor through itself.
- Drive a
VisitorMut
over this datastructure. - An interface for visiting arbitrary data structures.
- An interface for visiting data structures and mutating them during the visit.
Functions§
- Similar to visitor_fn, but the closure will only be called on Event::Enter.
- Similar to
visitor_fn_mut
, but the closure will only be called on Event::Enter. - Create a visitor that only visits items of some specific type from a function or a closure.
- Create a visitor that only visits items and mutates them with the given function
Derive Macros§
- See
Drive
. - See
DriveMut
. - See
Visitor
. - See
VisitorMut
.